#pragma once
#include <memory>
#include <string>

#include "../Messages/BaseMessages.h"
#include <boost/system/error_code.hpp>

namespace AlgoTrading
{
	namespace ConnectionLibrary
	{

		class NotificationHandler
		{
		public:
			virtual void OnNotification(const AlgoTrading::Messages::NotificationMessage& notification) = 0;
			virtual void OnRequestResponse(const AlgoTrading::Messages::RequestResponse& response) = 0;
			virtual void OnError(const boost::system::error_code& error) = 0;
			virtual void OnDisconnect() = 0;
		};

		class FeedConnector
		{
		public:
			virtual boost::system::error_code Connect(const std::string& host, const std::string& serviceNameOrPort) = 0;
			virtual void Disconnect() = 0;
			virtual void SendRequest(const AlgoTrading::Messages::RequestWithoutResponse& request) = 0;
			virtual void SendRequest(const AlgoTrading::Messages::RequestWithResponse& request) = 0;

			virtual ~FeedConnector() = 0;
		};

		class ClientConnectionLibrary
		{
		public:
			virtual void Start() = 0;
			virtual void Stop() = 0;
			virtual std::auto_ptr<FeedConnector> CreateFeedConnector(std::tr1::weak_ptr<NotificationHandler> notificationHandler) = 0;
			virtual ~ClientConnectionLibrary() = 0;
		};

		class ClientNotificationProcessor
		{
		public:
			virtual void SendNotification(const AlgoTrading::Messages::NotificationMessage&) = 0;
			virtual void SendRequestResponse(const AlgoTrading::Messages::RequestResponse&) = 0;
		};

		typedef std::tr1::shared_ptr<ClientNotificationProcessor> ClientNotificationProcessorPtr;

		class ClientRequestProcessor
		{
		public:
			virtual void OnRequest(const AlgoTrading::Messages::RequestWithResponse& request) = 0;
			virtual void OnRequest(const AlgoTrading::Messages::RequestWithoutResponse& request) = 0;
			virtual ~ClientRequestProcessor() = 0;
		};

		typedef std::tr1::shared_ptr<ClientRequestProcessor> ClientRequestProcessorPtr;

		class ClientConnectionAcceptor
		{
		public:
			virtual ClientRequestProcessorPtr OnClientConnected(std::tr1::weak_ptr<ClientNotificationProcessor> client) = 0;
			virtual void OnError(const boost::system::error_code& error) = 0;
			virtual void OnDisconnect() = 0;
			virtual ~ClientConnectionAcceptor() = 0;
		};

		typedef std::tr1::shared_ptr<ClientConnectionAcceptor> ClientConnectionAcceptorPtr;

		class ServerConnectionLibrary
		{
		public:
			virtual void Start() = 0;
			virtual void Stop() = 0;
			virtual ~ServerConnectionLibrary() = 0;
		};

		//Helper class. Derive from this class to accept client connections.
		class ClientHandlerBase : public ClientRequestProcessor
		{
		public:
			virtual ~ClientHandlerBase();

			virtual ClientRequestProcessorPtr OnClientConnected(std::tr1::weak_ptr<ClientNotificationProcessor> client);
			virtual void SendNotification(const AlgoTrading::Messages::NotificationMessage&);
			virtual void SendRequestResponse(const AlgoTrading::Messages::RequestResponse&);

			virtual std::tr1::shared_ptr<ClientRequestProcessor> GetGlientRequestProcessor() = 0;

		protected:
			std::tr1::weak_ptr<ClientNotificationProcessor> client;
		};

		std::auto_ptr<ClientConnectionLibrary> CreateClientConnectionLibraryInstance();
		std::auto_ptr<ServerConnectionLibrary> CreateServerConnectionLibraryInstance(ClientConnectionAcceptorPtr acceptor, const std::string& address, const std::string& port);
	}

}
